﻿/// \file Fişierul principal al aplicaţiei pentru PC.	
// ======================================================================================
//										HEADERS
// ======================================================================================
#include "stdafx.h"
#include "BluesoleilInterface.h"
#include "BTComputer.h"

//	System Tray needed
#include "shellapi.h"
// ======================================================================================
//										DECLARATIONS
// ======================================================================================

/// \brief Funcţia ce tratează evenimente de pe linia serială
void SerialListenDog(uint32 object, uint32 event);

// ======================================================================================
//										GLOBAL VARS
// ======================================================================================
///	Handler al ferestrei principale
HWND _mainDialogHandle;
HRESULT hr;		

/// Parametru de intrare pentru funcţia SendInput. Conţine codul tastei şi starea sa. 
/// Trimit succesiv PRESS/RELEASE
INPUT simulatedKey[2];

/// Parametru de intrare pentru funcţia SendInput. 
/// Permite modelarea evenimentelor de la mouse.
INPUT simulatedMouse;

/// Variabilă folosită de SetCursorPos pentru a modifica poziţia cursorului pe ecran
POINT mousePosition;

/// stările posibile ale funcţiei de decodificare a datelor primite pe linia serială
enum	STATE { IDLE, KEY, MOUSE, X, Y};

/// starea curentă a decodificatorului
STATE currentState = IDLE;

const char g_szClassName[] = "BTComputer";
bool run = true;

/// \brief Bluesoleil implementation
/// \note Implementată pe PC
BluesoleilInterface		bluesoleilBT;

/// \brief Librăria curentă folosită pentru manipularea comunicaţiei prin Bluetooth
/// \note Sunt posibile Bluesoleil, Microsoft.
BluetoothStack&			currentBT = bluesoleilBT;

// ======================================================================================
/// \brief Definiţii utilizate în implementarea funcţiilor System Tray
/// \note Două declaraţii în care reţinem titlul aplicăţiei şi mesajul de informare 
// ======================================================================================
/// \brief Titlul aplicaţiei 
#define THIS_TITLE          "Remote Media Control"
/// \brief Descriere a aplicaţiei
/// \note Remote Control de pe PDA. Acesta controlează:
///	- volumul calculatorului 
///	- implementează taste speciale pentru controlul tip player media 
///	- permite utilizarea PDA-ului ca un mouse
#define HELP_ABOUT "Remote Control de pe PDA. Acesta controlează: \n\
- volumul calculatorului \n\
- implementează taste speciale pentru controlul tip player media \n\
- permite utilizarea PDA-ului ca un mouse\n\
"
// ======================================================================================
/// \brief Variabilă booleană uitilizată pentru a indica dacă un mesaj va fi sau nu afişat.
// ======================================================================================
static BOOL g_bModalState       = FALSE;

// ======================================================================================
/// \brief Tag-uri utilizate în System Tray
/// - Tray icon
/// - Comenzi
// ======================================================================================
enum {
    // Tray icon
    ID_TRAYICON         = 1,

    APPWM_TRAYICON      = WM_APP,
    APPWM_NOP           = WM_APP + 1,

    // Comenzi
    ID_ABOUT            = 2000,
    ID_EXIT,
};

// ======================================================================================
// Prototipuri ale funcţiilor System Tray.
// ======================================================================================

void    AddTrayIcon( HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon, 
                     LPSTR pszToolTip );
void    RemoveTrayIcon( HWND hWnd, UINT uID);
/// \brief Funcţie de modificare a icon-ului folosit pentru aplicaţie în System Tray
void    ModifyTrayIcon( HWND hWnd, UINT uID, UINT uIcon, LPSTR pszToolTip );

//HANDLE   LoadSmallIcon( HINSTANCE hInstance, UINT uID );

BOOL    ShowPopupMenu( HWND hWnd, POINT *curpos, int wDefaultItem );
void    OnInitMenuPopup( HWND hWnd, HMENU hMenu, UINT uID );

BOOL    OnCommand( HWND hWnd, WORD wID, HWND hCtl );

void    OnTrayIconMouseMove( HWND hWnd );
void    OnTrayIconRBtnUp( HWND hWnd );
void    OnTrayIconLBtnUp( HWND hWnd );
void    OnTrayIconLBtnDblClick( HWND hWnd );

void    OnClose( HWND hWnd );

// ======================================================================================
///	\brief Tratează evenimentele primite de la sistemul de operare
/// - Iniţializează bluetoothul
/// - Minimizează în SystemTray aplicaţia 
// ======================================================================================
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
		//------
		case WM_CREATE:
		{
			_mainDialogHandle = hWnd;
			AddTrayIcon( hWnd, ID_TRAYICON, APPWM_TRAYICON, 0, THIS_TITLE );
		    if( bluesoleilBT.InitBluetooth() == OK )
			{
				bluesoleilBT.serialEye.setManager( SerialListenDog );
				currentBT = bluesoleilBT;
			}
			return (INT_PTR)TRUE;
		}
		break;
		//------
		case APPWM_TRAYICON:
            SetForegroundWindow( hWnd );
			//------
            switch ( lParam ) {
				//When the cursor moves over the tray
                case WM_MOUSEMOVE:
                    OnTrayIconMouseMove( hWnd );
                break;
				//Right click the mouse
                case WM_RBUTTONUP:
                    OnTrayIconRBtnUp( hWnd );
                break;
				//------
				case WM_LBUTTONDBLCLK:
                   OnTrayIconLBtnDblClick( hWnd );
                break;
            }
            break;
		//------
		case WM_COMMAND:
			switch(LOWORD(wParam)){
				//------
				case ID_ABOUT:
					g_bModalState = TRUE;
					MessageBox( hWnd, _T(HELP_ABOUT), _T(THIS_TITLE), MB_ICONINFORMATION | MB_OK );
					g_bModalState = FALSE;
				break;
				//------
				case ID_EXIT:
					PostMessage(hWnd, WM_CLOSE, 0, 0 );
				break;
				//------
				case ID_FILE_EXIT:
					PostMessage(hWnd, WM_CLOSE, 0, 0);
				break;
				//------
				case ID_STUFF_GO:
				break;
			}
			break;
	
		//------
		case WM_CLOSE:
			RemoveTrayIcon(hWnd, ID_TRAYICON);
			OnClose( hWnd );
			DestroyWindow(hWnd);
		break;
		//------
		case WM_DESTROY:
			PostQuitMessage(0);
		break;
		
		default: 
			return DefWindowProc(hWnd, msg, wParam, lParam);
	}
	return 0;
}

// ======================================================================================
///	\brief Decodifică datele primite pe linia serială 
// ======================================================================================
void OnDataArrival(int size, char *buffer)
{
	if ((size > 0) && ( buffer != NULL ))
    {
		switch( currentState )
		{
		case IDLE:
			
			if( buffer[0] == KEY_INPUT )
			{
				currentState = KEY;
				break;
			}

			switch( buffer[0] )
			{
			case MOUSE_CLICK:
				simulatedMouse.type = INPUT_MOUSE;
				simulatedMouse.mi.dx = 0;
				simulatedMouse.mi.dy = 0;
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
				simulatedMouse.mi.dwExtraInfo = 0;
				simulatedMouse.mi.mouseData = 0;
				simulatedMouse.mi.time = 0;
				currentState = IDLE;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_LEFTUP;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				break;
			case MOUSE_DBCLICK:
				simulatedMouse.type = INPUT_MOUSE;
				simulatedMouse.mi.dx = 0;
				simulatedMouse.mi.dy = 0;
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
				simulatedMouse.mi.dwExtraInfo = 0;
				simulatedMouse.mi.mouseData = 0;
				simulatedMouse.mi.time = 0;
				currentState = IDLE;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_LEFTUP;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				break;
			case MOUSE_RIGHT:
				simulatedMouse.type = INPUT_MOUSE;
				simulatedMouse.mi.dx = 0;
				simulatedMouse.mi.dy = 0;
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
				simulatedMouse.mi.dwExtraInfo = 0;
				simulatedMouse.mi.mouseData = 0;
				simulatedMouse.mi.time = 0;
				currentState = IDLE;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				simulatedMouse.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
				SendInput( sizeof(simulatedMouse) / sizeof(INPUT) , &simulatedMouse , sizeof(INPUT) );
				break;
			case MOUSE_MOVE:
				currentState = X;
				break;
			}
		break;
		case KEY:
				// PRESS
				simulatedKey[0].type		= INPUT_KEYBOARD;
				simulatedKey[0].ki.wVk 		= buffer[0];
				// RELEASE
				simulatedKey[1].type		= INPUT_KEYBOARD;
				simulatedKey[1].ki.wVk 		= buffer[0];
				simulatedKey[1].mi.dwFlags	= KEYEVENTF_KEYUP;

				SendInput( sizeof(simulatedKey) / sizeof(INPUT) , simulatedKey , sizeof(INPUT) );
				currentState = IDLE;
				break;
		case X:
			GetCursorPos( & mousePosition );
			mousePosition.x -= 2 * buffer[0];
			currentState = Y;
			break;
		case Y:
			mousePosition.y -= 2 * buffer[0];
			SetCursorPos( mousePosition.x, mousePosition.y );
			currentState = IDLE;
			break;
		}
    }
}
// ======================================================================================
//	Serial Event Listener
// ======================================================================================
void SerialListenDog(uint32 object, uint32 event)
{
char *buffer;
    int   size;
    Tserial_event *com;

    com = (Tserial_event *) object;
    if (com!=0)
    {
        switch(event)
        {
            case  SERIAL_CONNECTED  :
                                        printf("Connected ! \n");
                                        break;
            case  SERIAL_DISCONNECTED  :
                                        printf("Disonnected ! \n");
                                        break;
            case  SERIAL_DATA_SENT  :
                                        printf("Data sent ! \n");
                                        break;
            case  SERIAL_RING       :
                                        printf("DRING ! \n");
                                        break;
            case  SERIAL_CD_ON      :
                                        printf("Carrier Detected ! \n");
                                        break;
            case  SERIAL_CD_OFF     :
                                        printf("No more carrier ! \n");
                                        break;
            case  SERIAL_DATA_ARRIVAL  :
                                        size   = com->getDataInSize();
                                        buffer = com->getDataInBuffer();
                                        OnDataArrival(size, buffer);
                                        com->dataHasBeenRead();
                                        break;
        }
    }
}
// ======================================================================================
//	MAIN
// ======================================================================================
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;
	HWND hWnd;
	MSG Msg;
	//Registering the Window Class
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.style		= 0;
	wc.lpfnWndProc  = WndProc;
	wc.cbClsExtra   = 0;
	wc.cbWndExtra	= 0; 
	wc.hInstance	= hInstance;
	wc.hIcon		= LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground =(HBRUSH)(COLOR_WINDOW + 8);
	//add the menu resource
	wc.lpszMenuName = MAKEINTRESOURCE(IDR_MYMENU);
	wc.lpszClassName = _T("myWindowClass");
	wc.hIconSm		= LoadIcon(NULL, IDI_APPLICATION);
	
	if( !RegisterClassEx( &wc ) )
	{
		MessageBox(NULL, _T("Window Registration Failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}
	//Creating the window
	hWnd = CreateWindowEx(
		WS_EX_CLIENTEDGE,
		_T("myWindowClass"),
		_T("Program de frecat menta"),
		WS_OVERLAPPEDWINDOW,
		CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 
		NULL, NULL, hInstance, NULL);

	if(hWnd == NULL)
	{
		MessageBox(NULL, _T("Window creation failed!"), _T("Error!"), MB_ICONEXCLAMATION | MB_OK);
		return 0;
	}
	//ShowWindow(hWnd, nCmdShow);
	//UpdateWindow(hWnd);

	//The message loop
	while(GetMessage(&Msg, NULL, 0, 0) > 0)
	{
		TranslateMessage(&Msg);
		DispatchMessage(&Msg);
	}
	return Msg.wParam;

}
// ======================================================================================
/// \brief Funcţie de adăugare a icon-ului folosit pentru aplicaţie în System Tray.
// ======================================================================================

void AddTrayIcon( HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon, 
                  LPSTR pszToolTip )
{
    NOTIFYICONDATA  nid;

    memset( &nid, 0, sizeof( nid ) );

    nid.cbSize              = sizeof( nid );
    nid.hWnd                = hWnd;
    nid.uID                 = uID;
	
    nid.uFlags              = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage    = uCallbackMsg;
	
    nid.hIcon               = LoadIcon(NULL, IDI_APPLICATION);

    Shell_NotifyIcon( NIM_ADD, &nid );
}

// ======================================================================================
/// \brief Funcţie de ştergere a icon-ului folosit pentru aplicaţie în System Tray.
// ======================================================================================
void RemoveTrayIcon( HWND hWnd, UINT uID )
{
    NOTIFYICONDATA  nid;

    memset( &nid, 0, sizeof( nid ) );

    nid.cbSize  = sizeof( nid );
    nid.hWnd    = hWnd;
    nid.uID     = uID;

    Shell_NotifyIcon( NIM_DELETE, &nid );
}

// ======================================================================================
///  \brief Crează şi afişează meniul pop-up când utilizatorul dă click dreapta pe icon-ul 
///  din System Tray.
// ======================================================================================
BOOL ShowPopupMenu( HWND hWnd, POINT *curpos, int wDefaultItem )
{
    HMENU   hPop        = NULL;
    int     i           = 0;
    WORD    cmd;
    POINT   pt;

    if ( g_bModalState )
        return FALSE;

    hPop = CreatePopupMenu();

    if ( ! curpos ) {
        GetCursorPos( &pt );
        curpos = &pt;
    }

    InsertMenu( hPop, i++, MF_BYPOSITION | MF_STRING, ID_ABOUT, L"About..." );
    InsertMenu( hPop, i++, MF_BYPOSITION | MF_STRING, ID_EXIT, L"Exit" );

    SetMenuDefaultItem( hPop, ID_ABOUT, FALSE );

    SetFocus( hWnd );

    SendMessage( hWnd, WM_INITMENUPOPUP, (WPARAM)hPop, 0 );

    cmd = TrackPopupMenu( hPop, TPM_LEFTALIGN | TPM_RIGHTBUTTON 
                            | TPM_RETURNCMD | TPM_NONOTIFY,
                          curpos->x, curpos->y, 0, hWnd, NULL );

    SendMessage( hWnd, WM_COMMAND, cmd, 0 );

    DestroyMenu( hPop );

    return cmd;
}
// ======================================================================================
/// \brief Această metodă este apelată în momentul în care butonul drept al mouse-ului 
/// este eliberat astfel executându-se acţiunile aferente acestui eveniment.
// ======================================================================================
void OnTrayIconRBtnUp( HWND hWnd )
{
    SetForegroundWindow( hWnd );

    ShowPopupMenu( hWnd, NULL, -1 );

    PostMessage( hWnd, APPWM_NOP, 0, 0 );
}
// ======================================================================================
/// \brief Această metodă este apelată în momentul unei duble apăsări consecutive a 
/// butonului stând al mouse-ului astfel executându-se acţiunile aferente acestui eveniment. 
// ======================================================================================
void OnTrayIconLBtnDblClick( HWND hWnd )
{
    SendMessage( hWnd, WM_COMMAND, ID_ABOUT, 0 );
}
// ======================================================================================
/// \brief Această metodă este apelată în momentul în care butonul stâng al mouse-ului 
/// este eliberat astfel executându-se acţiunile aferente acestui eveniment.
// ======================================================================================
void  OnTrayIconLBtnUp( HWND hWnd )
{
	SendMessage( hWnd, WM_SYSCOMMAND, SW_SHOW, 0 );
}

// ======================================================================================
/// \brief Această metodă este apelată în momentul iniţializării ferestrei de pop-up, 
/// nefolosită momentan
// ======================================================================================
void OnInitMenuPopup( HWND hWnd, HMENU hPop, UINT uID )
{	
}
// ======================================================================================
/// \brief Această metodă este apelată în momentul mişcării mouse-ului pe meniul pop-up 
/// nefolosită momentan
// ======================================================================================
void OnTrayIconMouseMove( HWND hWnd )
{
    
}
// ======================================================================================
/// \brief Această metodă este este apelată în momentul închiderii aplicaţiei în System
/// Tray
// ======================================================================================
void OnClose( HWND hWnd )
{
    //  Şterge icon din System Tray
    RemoveTrayIcon( hWnd, ID_TRAYICON );
}

